package javaer.starter.core.handler;

import com.google.common.base.Charsets;
import com.google.common.collect.Sets;
import javaer.starter.base.domain.dto.TemplateDTO;
import javaer.starter.base.service.TemplateService;
import javaer.starter.constant.BuiltInKeywords;
import javaer.starter.core.render.TemplateRenderHolder;
import javaer.starter.util.FileUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;
import java.nio.file.Path;
import java.util.HashSet;
import java.util.Set;

/**
 * @author yangzhen
 * @date 2023/6/15 14:27
 * @since 1.0.0
 */
@Slf4j
@Component("dynamicTemplateHandler")
public class DynamicTemplateHandler implements ITemplateHandler {

    @Resource
    private TemplateService templateService;

    @Resource
    private TemplateRenderHolder templateRenderHolder;

    public DynamicTemplateHandler() {
    }

    @Override
    public void handle(ModuleContext moduleContext) {
        try {
            // 创建目录
            getProjectModulePath(moduleContext);
            // 创建模板文件
            Set<TemplateDTO> templates = createTemplates(moduleContext);

            // 渲染模板文件
            renderTemplates(moduleContext, templates);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public Set<TemplateDTO> createTemplates(ModuleContext moduleContext) throws IOException {
        Set<TemplateDTO> templates = templateFiltering(moduleContext);
        if (CollectionUtils.isNotEmpty(templates)) {
            for (TemplateDTO template : templates) {
                Path templatePath = getTemplatePath(moduleContext, template);
                String resolveName = template.getTemplateName();
                template.setResolveName(resolveName);
                // 创建模板文件
                createTemplate(resolveName, template.getContent(), templatePath);
            }
        }
        return templates;
    }

    /**
     * 初始化项目模块路径
     * 如：/tmp/project/{artifactId}/xxx-starter
     *
     * @param moduleContext
     * @return
     * @throws IOException
     */
    protected void getProjectModulePath(ModuleContext moduleContext) throws IOException {
        Path modulePath = moduleContext.getProjectPath().resolve(moduleContext.getModuleArtifactId());
        FileUtil.createDirsIfNotExists(modulePath);
        moduleContext.setModulePath(modulePath);
    }

    /**
     * 初始化模板路径
     *
     * @param moduleContext
     * @param template
     * @return
     * @throws IOException
     */
    protected Path getTemplatePath(ModuleContext moduleContext, TemplateDTO template) throws IOException {
        Path templatePath = moduleContext.getTemplatePath();
        if (StringUtils.isNotBlank(template.getSourceDirectory())) {
            templatePath = templatePath.resolve(template.getSourceDirectory());
        }
        if (StringUtils.isNotBlank(template.getRelativePath())) {
            templatePath = templatePath.resolve(template.getRelativePath());
        }
        FileUtil.createDirsIfNotExists(templatePath);
        return templatePath;
    }

    /**
     * 渲染模板
     *
     * @param moduleContext
     * @param templates
     * @throws Exception
     */
    protected void renderTemplates(ModuleContext moduleContext, Set<TemplateDTO> templates) throws Exception {
        for (TemplateDTO template : templates) {
            templateRenderHolder.render(moduleContext, template);
        }
    }


    /**
     * 查询模板并过滤
     *
     * @param moduleContext
     * @return
     */
    private Set<TemplateDTO> templateFiltering(ModuleContext moduleContext) {
        Set<TemplateDTO> currentModuleTemplates = templateService.findByTypeId(moduleContext.getTypeId(), moduleContext.getModuleId());
        if (currentModuleTemplates == null || currentModuleTemplates.isEmpty()) {
            return Sets.newHashSet();
        }
        Set<TemplateDTO> moduleTemplates = new HashSet<>();
        currentModuleTemplates.forEach(t -> {
            String depId = t.getDepId();
            if (isNeedTemplate(depId, moduleContext)) {
                moduleTemplates.add(t);
            }
        });

        Set<TemplateDTO> moduleAllTemplates = templateService.findByTypeId(moduleContext.getTypeId(), BuiltInKeywords.MODULE_ALL.getValue());
        if (CollectionUtils.isNotEmpty(moduleAllTemplates)) {
            moduleAllTemplates.forEach(t -> {
                String depId = t.getDepId();
                if (isNeedTemplate(depId, moduleContext)) {
                    t.setModuleId(moduleContext.getModuleId());
                    moduleTemplates.add(t);
                }
            });
        }
        return moduleTemplates;
    }

    private boolean isNeedTemplate(String depId, ModuleContext moduleContext) {
        // 校验模板关联的depId是否存在，如果不存在，则不需要渲染此模板
        boolean need = true;
        need = need && (StringUtils.isBlank(depId) ? true : moduleContext.getDependencyIdSet().contains(depId));
        return need;
    }

    /**
     * 创建模板文件
     *
     * @param resolveName
     * @param data
     * @param templatePath
     * @throws IOException
     */
    protected void createTemplate(String resolveName, String data, Path templatePath) throws IOException {
        // 如果模板文件的data不为空，渲染模版内容
        if (StringUtils.isNotBlank(data)) {
            Path filePath = templatePath.resolve(resolveName);
            com.google.common.io.Files.asCharSink(filePath.toFile(), Charsets.UTF_8).write(data);
        } else {
            // 否则创建空文件
            FileUtil.createFileIfNotExists(templatePath, resolveName);
        }
    }

    /**
     * 创建模块模板路径
     *
     * @param moduleContext
     * @return
     * @throws IOException
     */
//    protected Path createModuleTemplateRealPath(ModuleContext moduleContext) throws IOException {
//        String typeName = moduleContext.getTypeName();
//        String moduleName = moduleContext.getModuleName();
//        Path path = moduleContext.getTemplatePath().resolve(typeName).resolve(moduleName);
//        FileUtil.createDirsIfNotExists(path);
//        return path;
//    }
}
